<template>
    <div class="flow-chart-container" :class="{'readOnly': readOnly}">
        <div class="canvas-container">
            <tool-bar v-if="!readOnly" :bpmnModeler="bpmnModeler" :elementSelector="elementSelector" :xml="xml" />
<!--            <el-button @click="getNodeArr">点击调试</el-button>-->
            <div ref="canvas" class="canvas" v-if="showCanvas"></div>
        </div>
        <add-operation :nodeId="nodeId" :readOnly="readOnly" :nodeType="nodeType" :nodeInfo="nodeInfo" @updateNode="updateNode" />
    </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import Modeler from 'bpmn-js/lib/Modeler';
import 'bpmn-js/dist/assets/diagram-js.css'; // 左边工具栏以及编辑节点的样式
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css';
import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css';
import 'bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css';
import customTranslate from "./zhcn/customTranslate";
import customModule from './custom/only-palette';
import { activitiJson } from "./custom/activiti";
import { xmlStr } from './xmlData';
import ToolBar from './tool-bar.vue';
import AddOperation from "../add-operation/index.vue";

@Component({
    components: {
        ToolBar,
        AddOperation
    }
})
export default class FlowChart extends Vue {
    @Prop({ default: false }) private readOnly!: boolean
    @Prop({ default: false }) private isDetail!: boolean
    @Prop({ default: "" }) private id: any
    @Prop({ default: false }) private isCheck!: boolean
    @Watch("id")
    onChangeId() {
        this.showCanvas = false;
        this.$nextTick(() => {
            this.showCanvas = true;
            this.$nextTick(() => {
                if (this.id) this.init();
            });
        });
    }

    // 流程对象
    bpmnModeler: any = null
    // 保存的流程
    xml = ""
    svg = ""
    // 当前选中内容
    elementSelector: any[] = []
    // 当前选中id
    nodeId = ""
    // 当前节点类型
    nodeType = ""
    // 当前节点信息
    nodeInfo: any = {}
    showCanvas = true
    handleArr: any[] = []
    approvalArr: any[] = []
    canNext = false

    mounted() {
        if (this.isCheck) {
            if (this.id) {
                this.init();
            }
        } else {
            this.init();
        }
    }

    // 创建流程图
    init() {
        let additionalModules = [];
        if (this.readOnly) {
            additionalModules = [
                {
                    // 禁用滚轮滚动
                    zoomScroll: ['value', ''],
                    // 禁止拖动线
                    bendpoints: ['value', ''],
                    // 禁止点击节点出现contextPad
                    contextPadProvider: ['value', ''],
                    // 禁止双击节点出现label编辑框
                    labelEditingProvider: ['value', '']
                }
            ];
        } else {
            const customTranslateModel = {
                translate: ["value", customTranslate]
            };
            additionalModules = [
                customModule,
                customTranslateModel,
                {
                    labelEditingProvider: ['value', '']
                }
            ];
        }
        this.bpmnModeler = new Modeler({
            container: this.$refs.canvas,
            keyboard: {
                bindTo: document
            },
            propertiesPanel: {},
            additionalModules: additionalModules,
            moddleExtensions: {
                activitiJson
            }
        });

        this.createNewDiagram();
        this.initEvent();
    }

    // 导入画布
    async createNewDiagram(id?: any) {
        if (id) {
            this.id = id;
        }
        if (this.id) {
            const res = await this.$server["process/getProcessInfo"]({
                data: {
                    id: this.id
                },
                responseType: ""
            });
            this.xml = res.data;
        }
        await (this.bpmnModeler as any).importXML(this.xml || xmlStr);
        (this.bpmnModeler as any).get('canvas').zoom('fit-viewport', 'auto');
        this.saveXML();
    }

    // 初始化事件
    initEvent() {
        const eventBus: any = (this.bpmnModeler as any).get('eventBus');
        eventBus.on('selection.changed', (e: any) => {
            this.elementSelector = e.newSelection;
            if (!this.elementSelector.length) {
                this.nodeId = "";
                this.nodeType = "";
            } else {
                this.addActivitiAttr(this.elementSelector[0].id);
            }
        });
        eventBus.on('element.click', (e: any) => {
            console.log(e, "click");
            this.nodeInfo = { id: e.element.id };
            this.getNode(e);
        });
        eventBus.on('element.changed', (e: any) => {
            console.log(e, "改变");
            if (this.elementSelector.length) {
                this.getNode(e);
            }
            /* const { type, businessObject } = e.element;
            if (type === "bpmn:SequenceFlow" && businessObject.conditionExpression) {
                // businessObject.targetRef.$attrs.taskType
                if (businessObject.sourceRef.$attrs.taskType === "Handle") {
                    businessObject.conditionExpression = null;
                    businessObject.name = "";
                }
            } */
        });
    }

    // 添加经办人/审批人属性
    addActivitiAttr(id: any) {
        const modeling = (this.bpmnModeler as any).get("modeling");
        const shape = (this.bpmnModeler as any).get("elementRegistry").get(id || this.nodeId);
        const type: any = shape.businessObject.$attrs.taskType;
        if (type === "Handle") {
            modeling.updateProperties(shape, { "activiti:assignee": "${assignee}" }); // eslint-disable-line
            modeling.updateProperties(shape, { "activiti:category": "handle" });
        } else if (type === "Approval") {
            modeling.updateProperties(shape, { "activiti:assignee": "${auditor}" }); // eslint-disable-line
            modeling.updateProperties(shape, { "activiti:category": "approval" });
        }
    }

    // 获取节点
    getNode(e: any) {
        if (this.isDetail) return;
        if (this.getNodeType(e)) {
            const selected = e.element.businessObject.assignee;
            this.nodeInfo = {
                name: e.element.businessObject.name,
                selectedList: selected ? selected.split(",") : []
            };
            this.nodeId = e.element.id;
            this.nodeType = this.getNodeType(e) || "";
        } else if (e.element.type === "bpmn:SequenceFlow") {
            const { type, businessObject } = e.element;
            if (type === "bpmn:SequenceFlow" && (businessObject.sourceRef.$attrs.taskType === "Approval" || businessObject.sourceRef.$attrs["activiti:category"] === "approval")) {
                this.nodeId = e.element.id;
                this.nodeType = "connect";
                const conditionExpression = e.element.businessObject.conditionExpression;
                this.nodeInfo = {
                    rule: conditionExpression ? conditionExpression.body : ""
                };
            } else {
                this.nodeId = "";
                this.nodeInfo = {};
            }
        } else {
            this.nodeId = "";
            this.nodeType = "";
        }
    }

    // 修改节点
    updateNode(data: any, id: any) {
        if (this.readOnly) return false;
        const modeling = (this.bpmnModeler as any).get("modeling");
        const shape = (this.bpmnModeler as any).get("elementRegistry").get(id || this.nodeId);
        if (data.type === "connectLine") {
            const moddle = (this.bpmnModeler as any).get("moddle");
            const conditionExpression = moddle.create("bpmn:FormalExpression", { body: data.data.rule });
            modeling.updateProperties(shape, {
                conditionExpression: conditionExpression,
                name: data.data.name
            });
        } else {
            modeling.updateProperties(shape, data.data);
        }
    }

    // 保存为xml
    async saveXML() {
        const res = await (this.bpmnModeler as any).saveXML({ format: true });
        this.xml = res.xml.toString();
        const resSvg = await (this.bpmnModeler as any).saveSVG({ format: true });
        this.svg = resSvg.svg.toString();
    }

    // 提交
    async submit(callback: any) {
        this.xml = "";
        // 需要校验的节点type
        // const needPeople = ["handle", "approval", "copy"];
        const elementRegistry = (this.bpmnModeler as any).get('elementRegistry');
        // 修改默认根节点id/key值
        if (elementRegistry.get("Process_0")) {
            this.updateNode({ data: { id: "Process_" + Math.round(new Date().getTime() / 1000).toString() } }, "Process_0");
        }

        // 所有节点列表
        const nodeArr: any = [];
        Object.keys(elementRegistry._elements).forEach((key: any) => {
            nodeArr.push(elementRegistry._elements[key]);
        });

        // 开始节点数量
        const startNode = nodeArr.filter((item: any) => item.element && item.element.type === "bpmn:StartEvent");
        // 结束节点数量
        const endNode = nodeArr.filter((item: any) => item.element && item.element.type === "bpmn:EndEvent");
        if (startNode.length !== 1 || endNode.length !== 1) {
            this.$message.error("必须有一个开始节点和一个结束节点");
            callback();
            return;
        }

        // 节点处理
        this.getNodeArr();

        if (!this.canNext) return;

        // // 需要有自定义属性的节点（经办人）
        // const userTaskList = nodeArr.filter(
        //     (item: any) => this.getNodeType(item) && needPeople.includes(this.getNodeType(item) || "")
        // );
        // // 没有经办人的节点
        // const noName = userTaskList.filter((item: any) => !item.element.businessObject.assignee);
        // const flag = !noName.length;
        const flag = true;

        // if (!flag) {
        //     const nameArr = noName.map((item: any) => item.element.businessObject.name).join(",");
        //     this.$message.error(`请先选择"${nameArr}"节点的处理人员后再进行保存`);
        // }
        // this.setListener(endNode[0].element.id);

        await this.saveXML();
        // 根元素key
        const rootKey = nodeArr.filter((item: any) => item.element.type === "bpmn:Process")[0].element.id;
        callback(flag,
            {
                xml: this.xml,
                svg: this.svg,
                key: rootKey,
                jsonCustomer: {
                    handleArr: this.handleArr,
                    approvalArr: this.approvalArr
                }
            }
        );
    }

    // 给结束节点添加监听器
    setListener(id: any) {
        const shape = (this.bpmnModeler as any).get('elementRegistry').get(id);
        const bpmnFactory = (this.bpmnModeler as any).get('bpmnFactory');
        let extensionElements = shape.businessObject.get('extensionElements');
        if (!extensionElements) {
            extensionElements = bpmnFactory.create('bpmn:ExtensionElements', null);
            extensionElements.$parent = shape;
        }
        const length = extensionElements.get('values').length;
        for (let i = 0; i < length; i++) {
            // 清除旧值
            extensionElements.get('values').pop();
        }
        const executionListener = bpmnFactory.create('activiti:ExecutionListener', null);
        executionListener.$parent = shape;
        executionListener.$attrs.event = "end";
        executionListener.$attrs.class = "com.tianzuoyun.saas.activiti.listener.ProcessEndListener";
        extensionElements.get('values').push(executionListener);
        const modeling = (this.bpmnModeler as any).get('modeling');
        modeling.updateProperties(shape, {
            extensionElements: extensionElements
        });
    }

    // 获取自定义属性
    get$attrs(e: any, name: any) {
        if (!e.element) return false;
        return e.element.businessObject.$attrs[name];
    }

    // 获取节点自定义type（经办审批）
    getNodeType(e: any) {
        if (!e.element || !e.element.businessObject.name) return false;
        if (this.get$attrs(e, "activiti:category") === "handle") {
            return "handle";
        }
        if (this.get$attrs(e, "activiti:category") === "approval") {
            return "approval";
        }
        return false;
    }

    // 获取所有需要人的节点
    getAllNode() {
        // 需要校验的节点type
        const needPeople = ["handle", "approval", "copy"];
        const elementRegistry = (this.bpmnModeler as any).get('elementRegistry');
        // 所有节点列表
        const nodeArr: any = [];
        Object.keys(elementRegistry._elements).forEach((key: any) => {
            nodeArr.push(elementRegistry._elements[key]);
        });
        // 需要有自定义属性的节点（经办人）
        const userTaskList = nodeArr.filter(
            (item: any) => this.getNodeType(item) && needPeople.includes(this.getNodeType(item) || "")
        );
        return userTaskList;
    }

    getNodeArr() {
        this.handleArr = [];
        this.approvalArr = [];
        const allArr: any[] = [];
        const allNode = this.getAllNode();
        const firstNode = allNode.filter((item: any) => this.getFirstNode(item) && this.get$attrs(item, "activiti:category") === "handle");
        if (firstNode.length) {
            allArr.push({
                name: firstNode[0].element.businessObject.name,
                id: firstNode[0].element.businessObject.id,
                type: this.get$attrs(firstNode[0], "activiti:category")
            });
        } else {
            this.$message.error("开始节点后必须连接一个经办节点!");
            return;
        }
        for (let i = 0; i < allNode.length; i++) {
            for (let j = 0; j < allNode.length; j++) {
                if (this.getPreNode(allNode[j], allArr[allArr.length - 1].id)) {
                    allArr.push({
                        name: allNode[j].element.businessObject.name,
                        id: allNode[j].element.businessObject.id,
                        type: this.get$attrs(allNode[j], "activiti:category")
                    });
                    break;
                }
            }
        }
        const handleArr =
            allArr.filter((item: any) => item.type === "handle").map((item: any, index: number) => {
                return {
                    ...item,
                    sort: index + 1
                };
            });
        const approvalArr =
            allArr.filter((item: any) => item.type === "approval").map((item: any, index: number) => {
                return {
                    ...item,
                    sort: index + 1
                };
            });
        this.handleArr = handleArr;
        this.approvalArr = approvalArr;
        handleArr.forEach((item: any) => {
            this.updateNode({ type: "handle", data: { "activiti:assignee": "${assignee" + item.sort + "}" } }, item.id);
        });
        approvalArr.forEach((item: any) => {
            this.updateNode({ type: "approval", data: { "activiti:assignee": "${auditor" + item.sort + "}" } }, item.id);
        });
        this.canNext = true;
    }

    // 获取指定节点的上一节点信息
    getPreNode(e: any, id: any) {
        return e.element.incoming[0].source.id === id;
    }

    // 判断是否是开始节点下的第一个节点
    getFirstNode(e: any) {
        return e.element.incoming.length && e.element.incoming[0].source.type === "bpmn:StartEvent";
    }
}
</script>
<style lang="scss" scoped>
.flow-chart-container {
    display: flex;
    justify-content: flex-start;
    align-items: flex-start;
    position: relative;
    .canvas-container {
        margin-right: 20px;
        .canvas {
            width: 925px;
            height: 340px;
            border: 1px solid #C7CAD3;
            border-radius: 6px;
            background: #FAFAFA;
            box-shadow: 0px 1px 5px rgba(0, 0, 0, 0.13);
        }
    }
    &.readOnly {
        /deep/.djs-palette, .djs-overlay.djs-overlay-context-pad {
            display: none;
        }
    }
}
</style>
